/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { KEYBOARD_KEY } from '@app-cad/common/Constants';
import { Line3, Object3D, Vector3 } from 'three-legacy';

import {
  BaseCommand,
  CENTEREVENTS,
  CSLine,
  CSPoint,
  css2dLabel,
  EventsRes,
  MathTool,
  MouseStyle,
  POINT_TYPE,
  SceneGraph,
} from '@amcax/base';
import { Picker3D, PickerMgr, Snaper } from '@amcax/renderer';
import { eventCenterManager } from '@app-base/common/events/EventCenterManager';
import { ctx2 } from '@app-cad/module';
import { useEffect } from 'react';

// 变量定义
let close: () => void;
let sceneSetup;
let toolsGroup;
let measureGroup: Object3D;
let step = 0;
let point1, point2;
let lengthMark;
let lengthLabel;

let hoverPointVec;
let VerticalPoint;

let hoverEdge; //模型hover的边
let lineObj; //延长辅助线
let lineObjmove1; ///延长辅助线
let lineObjmove; ///延长辅助线
let nearPoint; //垂线交点
let linePoint1, linePoint2; //hover的边的端点

let centerPoint; //圆心预览点
let radiusObjMove; //半径辅助线

let geomInfo: any; //边的信息
const measureState = {
  //测量状态
  Xlock: 'xlock',
  Ylock: 'ylock',
  Zlock: 'zlock',
  Default: '',
};
const colorState = {
  //不同状态线条颜色
  Xlock: 0xeb3316,
  Ylock: 0x22da90,
  Zlock: 0x3e40fe,
  Vertical: 0xe64980,
  Default: 0x27292a,
};
let MState = '';

function reset() {
  resetVaria();
}

function resetVaria() {
  step = 0;
  point1 = null;
  point2 = null;
  lengthMark = null;
  lengthLabel = null;
  hoverPointVec = null;
  VerticalPoint = null;
  lineObjmove = null;
  lineObjmove1 = null;

  centerPoint = null;
  radiusObjMove = null;
}

function findNearPoint(point, lineStart, lineEnd) {
  //求垂线交点
  const line = new Line3(lineStart, lineEnd);
  const nearestPoint = new Vector3();
  line.closestPointToPoint(point, false, nearestPoint);
  return nearestPoint;
}

function handlePoint1(point1, point2) {
  //点状态处理函数，根据不同的状态返回不同的终点
  if (MState == 'xlock') {
    return new Vector3(point2.x, point1.y, point1.z);
  }
  if (MState == 'ylock') {
    return new Vector3(point1.x, point2.y, point1.z);
  }
  if (MState == 'zlock') {
    return new Vector3(point1.x, point1.y, point2.z);
  }
  return point2;
}

function handleColor() {
  //点状态处理函数，根据不同的状态返回不同的终点
  if (MState == 'xlock') {
    return colorState.Xlock;
  }
  if (MState == 'ylock') {
    return colorState.Ylock;
  }
  if (MState == 'zlock') {
    return colorState.Zlock;
  }
  return colorState.Default;
}

function findMid(point1, point2) {
  //点状态处理函数，根据不同的状态返回不同的终点
  return new Vector3(
    (point1.x + point2.x) / 2,
    (point1.y + point2.y) / 2,
    (point1.z + point2.z) / 2,
  );
}

// 判断点是否在线段之上
function inLine(startPoint, endPoint, point) {
  const lineDirection = new Vector3().subVectors(endPoint, startPoint);
  const pointDirection = new Vector3().subVectors(point, startPoint);
  const dotProduct = lineDirection.dot(pointDirection);
  if (dotProduct >= 0 && dotProduct <= lineDirection.lengthSq()) {
    return true;
  } else {
    return false;
  }
}

// 寻找最近的点
function getClosestPoint(point1, point2, point3) {
  const distance1 = point1.distanceTo(point3);
  const distance2 = point2.distanceTo(point3);
  if (distance1 < distance2) {
    return point1;
  } else {
    return point2;
  }
}

const onMouseMove = (e: EventsRes) => {
  if (e.button.buttonDown) {
    return;
  }
  const pickRes = PickerMgr.getPicker<Picker3D>('3d').pick(e, {
    line: true,
    face: true,
  });
  let nowTakenPoint;
  if (pickRes) {
    nowTakenPoint = Snaper.snapKeyPoint(e, { lineCross: false });
  }
  if (nowTakenPoint) {
    hoverPointVec = nowTakenPoint.vector;
    VerticalPoint?.hide();
    lineObjmove1?.setVertexs([hoverPointVec, hoverPointVec]);
    lineObjmove?.setVertexs([hoverPointVec, hoverPointVec]);
    // 如果拾取到了点，就隐藏圆弧相关的预览
    if (radiusObjMove) {
      radiusObjMove.destroy();
      radiusObjMove = null;
    }
    if (centerPoint) {
      centerPoint.hide();
      centerPoint = null;
    }
  } else {
    if (radiusObjMove) {
      radiusObjMove.destroy();
      radiusObjMove = null;
    }
    if (centerPoint) {
      centerPoint.hide();
      centerPoint = null;
    }
    VerticalPoint?.hide();
    lineObjmove1?.setVertexs([new Vector3(0, 0, 0), new Vector3(0, 0, 0)]);
    lineObjmove?.setVertexs([new Vector3(0, 0, 0), new Vector3(0, 0, 0)]);
    hoverPointVec = null;
  }
  if (point1 && step == 1) {
    // 获取当前鼠标在相机正视方向平面上的世界坐标
    const normal = sceneSetup.getCameraNormal();
    const mouseWvec = sceneSetup.screenToWorld(
      e.mouse.x,
      e.mouse.y,
      normal,
      point1,
    ) as Vector3;
    hoverEdge = null;
    if (pickRes?.edgeId && hoverPointVec == null) {
      //当snap到点的时候不获取边
      geomInfo = null;
      hoverEdge = pickRes.edgeData; // 获取拾取到的那条边的坐标点（单一）
      // 直线
      if (hoverEdge.length == 2) {
        if (radiusObjMove) {
          radiusObjMove.destroy();
          radiusObjMove = null;
        }
        if (centerPoint) {
          centerPoint.hide();
          centerPoint = null;
        }
        linePoint1 = hoverEdge[0];
        linePoint2 = hoverEdge[1];
        // 计算垂线交点
        nearPoint = findNearPoint(point1, linePoint1, linePoint2);
        if (!VerticalPoint && !MathTool.isEqualVector(nearPoint, point1)) {
          // hover垂点
          VerticalPoint = new CSPoint({ pointType: POINT_TYPE.ONLINE });
          VerticalPoint.show();
          measureGroup.add(VerticalPoint);
          // 垂直辅助线预览
          const distance = nearPoint.distanceTo(point1);
          const attrs = {
            vertexs: [point1, nearPoint],
          };
          lineObjmove = new CSLine(attrs);
          lineObjmove.setDashSize((distance / 10) * 0.7); //设置虚线样式
          lineObjmove.setGapSize((distance / 10) * 0.3);
          lineObjmove.setDashed(true);
          lineObjmove.setColor(colorState.Vertical);
          lineObjmove.setLineWidth(1);
          lineObjmove.addTo(measureGroup);
          // 延长辅助线预览
          {
            const attrs = {
              vertexs: [
                inLine(linePoint1, linePoint2, nearPoint)
                  ? nearPoint
                  : getClosestPoint(linePoint1, linePoint2, nearPoint),
                nearPoint,
              ],
            };
            lineObjmove1 = new CSLine(attrs);
            const distance = attrs.vertexs[0].distanceTo(nearPoint);
            lineObjmove1.setDashSize((distance / 10) * 0.7);
            lineObjmove1.setGapSize((distance / 10) * 0.3);
            lineObjmove1.setDashed(true);
            lineObjmove1.setLineWidth(1);
            lineObjmove1.setColor(colorState.Vertical);
            lineObjmove1.setDashed(true);
            lineObjmove1.addTo(measureGroup);
          }
        } else if (!MathTool.isEqualVector(nearPoint, point1)) {
          // 辅助线更新
          VerticalPoint.show();
          VerticalPoint.setVertex(nearPoint);
          lineObjmove.setVertexs([point1, nearPoint]);
          const distance = point1.distanceTo(nearPoint);
          lineObjmove.setDashSize((distance / 10) * 0.7); //设置虚线样式
          lineObjmove.setGapSize((distance / 10) * 0.3);
          // 延长辅助线更新
          if (!inLine(linePoint1, linePoint2, nearPoint)) {
            lineObjmove1.setVertexs([
              getClosestPoint(linePoint1, linePoint2, nearPoint),
              nearPoint,
            ]);
            const distance = getClosestPoint(
              linePoint1,
              linePoint2,
              nearPoint,
            ).distanceTo(nearPoint);
            lineObjmove1.setDashSize((distance / 10) * 0.7);
            lineObjmove1.setGapSize((distance / 10) * 0.3);
          } else {
            lineObjmove1.setVertexs([nearPoint, nearPoint]);
          }
        } else {
          VerticalPoint?.hide();
          lineObjmove1?.setVertexs([nearPoint, nearPoint]);
          lineObjmove?.setVertexs([nearPoint, nearPoint]);
        }
      }
      // 曲线
      else {
        //获取线的几何信息
        // todo
        geomInfo = null; // 获取 几何信息
        if (geomInfo && geomInfo[0]?.radius) {
          // 如果拾取到了圆弧，就隐藏直线和点相关的预览
          VerticalPoint?.hide();
          lineObjmove1?.setVertexs([
            new Vector3(0, 0, 0),
            new Vector3(0, 0, 0),
          ]);
          lineObjmove?.setVertexs([new Vector3(0, 0, 0), new Vector3(0, 0, 0)]);
          // 圆心
          const center = new Vector3().fromArray(geomInfo[0].axis[0]);
          // 圆心的点
          if (!centerPoint) {
            centerPoint = new CSPoint({ pointType: POINT_TYPE.CIRCLE_CENTER });
            centerPoint.hoverOn();
            measureGroup.add(centerPoint);
          }
          // 半径
          const distance = geomInfo[0].radius;
          // 预览线
          const attrs = {
            vertexs: [point1, center],
          };
          if (!radiusObjMove) {
            radiusObjMove = new CSLine(attrs);
          }
          // 如果起点不是圆弧上的点，就不显示预览，如果是，就先死预览
          // if (Math.abs(distance - center.distanceTo(point1)) < 0.5) {
          // 虚线
          radiusObjMove.setVertexs(attrs.vertexs);
          radiusObjMove.setDashSize((distance / 10) * 0.7);
          radiusObjMove.setGapSize((distance / 10) * 0.3);
          radiusObjMove.setDashed(true);
          radiusObjMove.setColor(colorState.Vertical);
          radiusObjMove.setLineWidth(1);
          radiusObjMove.addTo(measureGroup);
          // 圆心
          centerPoint.setVertex(center);
          centerPoint.show();
          // } else {
          //   // 隐藏
          //   centerPoint.hide()
          //   radiusObjMove.setVertexs([center, center])
          // }
        }
      }
      //获取线的几何信息
      // todo
      geomInfo = null; // 获取 几何信息
      if (geomInfo && geomInfo[0]?.radius) {
        // 如果拾取到了圆弧，就隐藏直线和点相关的预览
        VerticalPoint?.hide();
        lineObjmove1?.setVertexs([new Vector3(0, 0, 0), new Vector3(0, 0, 0)]);
        lineObjmove?.setVertexs([new Vector3(0, 0, 0), new Vector3(0, 0, 0)]);
        // 圆心
        const center = new Vector3().fromArray(geomInfo[0].axis[0]);
        if (MathTool.isEqualVector(center, point1)) {
          // 圆心到圆弧
          const circleNormal = new Vector3().fromArray(geomInfo[0].axis[1]);
          const curVecOnPlane = sceneSetup.mouseOnPlane(
            e.mouse.x,
            e.mouse.y,
            circleNormal,
            point1,
          );
          // mouseWvec.projectOnPlane()
          const radiusNormal = curVecOnPlane
            .clone()
            .sub(point1.clone())
            .normalize();
          hoverPointVec = radiusNormal
            .setLength(geomInfo[0].radius)
            .add(point1.clone());
        } else {
          // 圆心的点
          if (!centerPoint) {
            centerPoint = new CSPoint({ pointType: POINT_TYPE.CIRCLE_CENTER });
            centerPoint.hoverOn();
            measureGroup.add(centerPoint);
          }
          // 半径
          const distance = geomInfo[0].radius;
          // 预览线
          const attrs = {
            vertexs: [point1, center],
          };
          if (!radiusObjMove) {
            radiusObjMove = new CSLine(attrs);
          }
          // 如果起点不是圆弧上的点，就不显示预览，如果是，就先死预览
          // if (Math.abs(distance - center.distanceTo(point1)) < 0.5) {
          // 虚线
          radiusObjMove.setVertexs(attrs.vertexs);
          radiusObjMove.setDashSize((distance / 10) * 0.7);
          radiusObjMove.setGapSize((distance / 10) * 0.3);
          radiusObjMove.setDashed(true);
          radiusObjMove.setColor(colorState.Vertical);
          radiusObjMove.setLineWidth(1);
          radiusObjMove.addTo(measureGroup);
          // 圆心
          centerPoint.setVertex(center);
          centerPoint.show();
          // } else {
          //   // 隐藏
          //   centerPoint.hide()
          //   radiusObjMove.setVertexs([center, center])
          // }
        }
      }
    }
    let handlePoint;
    if (hoverPointVec) {
      handlePoint = handlePoint1(point1, hoverPointVec);
    } else {
      handlePoint = handlePoint1(point1, mouseWvec);
    }
    let attrs = {
      vertexs: [point1, handlePoint],
    };
    let length = handlePoint.distanceTo(point1);
    if (!lengthMark) {
      attrs = {
        vertexs: [point1, handlePoint],
      };
      lengthMark = new CSLine(attrs);
      lengthMark.addTo(measureGroup);
      lengthMark.setColor(handleColor());
      const centerPosition = findMid(point1, handlePoint);
      length = MathTool.fixNumber(length, 0);
      lengthLabel = new css2dLabel({
        position: centerPosition,
        text: length,
        name: 'lengthLabel',
      });
      measureGroup.add(lengthLabel.labelObject);
    } else if (lengthMark) {
      lengthMark.setVertexs([point1, handlePoint]);
      lengthMark.setColor(handleColor());
      length = MathTool.fixNumber(length, 0);
      lengthLabel && lengthLabel.update(length, findMid(point1, handlePoint));
    }
    ctx2.viewer.requestRender();
  }
};

function pointerUpEvent(e: EventsRes) {
  if (!e.button.onLeft || !(hoverPointVec || hoverEdge)) {
    return;
  }
  if (step == 0) {
    point1 = hoverPointVec;
    step = 1;
  }
  //拾取到了点，测量点到点的距离
  else if (step == 1 && hoverPointVec) {
    point2 = hoverPointVec;
    const endPoint = handlePoint1(point1, point2);
    step = 0;
    //构建xyz方向锁定的辅助线
    const distance = endPoint.distanceTo(point2);
    if (distance) {
      const attrs = {
        vertexs: [point2, endPoint],
      };
      lineObj = new CSLine(attrs);
      lineObj.setDashSize((distance / 10) * 0.7); //设置虚线样式
      lineObj.setGapSize((distance / 10) * 0.3);
      lineObj.setDashed(true);
      lineObj.setColor(handleColor());
      lineObj.setLineWidth(1);
      lineObj.addTo(measureGroup);
    }
    //绘制距离
    if (lengthMark) {
      lengthMark.setVertexs([point1, endPoint]);
      let length = endPoint.distanceTo(point1);
      length = MathTool.fixNumber(length, 0);
      lengthLabel && lengthLabel.update(length, findMid(point1, endPoint));
    }
    //初始化数据
    VerticalPoint = null;
    lengthMark = null;
    point1 = null;
    point2 = null;
    Snaper.clear();
    hoverEdge?.withdraw?.();
    hoverEdge = null;
    MState = '';
    ctx2.viewer.requestRender();
  }
  //没有拾取到点，测量点到线的垂线距离
  else if (step == 1 && hoverEdge?.length <= 2) {
    point2 = nearPoint;
    step = 0;
    const endPoint = handlePoint1(point1, point2); //处理后的终点
    //构建xyz方向锁定的辅助线
    const distance = endPoint.distanceTo(point2);
    if (distance) {
      const attrs = {
        vertexs: [point2, endPoint],
      };
      lineObj = new CSLine(attrs);
      lineObj.setDashSize((distance / 10) * 0.7); //设置虚线样式
      lineObj.setGapSize((distance / 10) * 0.3);
      lineObj.setDashed(true);
      lineObj.setColor(handleColor());
      lineObj.setLineWidth(1);
      lineObj.addTo(measureGroup);
    }
    if (lengthMark) {
      lengthMark.setVertexs([point1, endPoint]);
      lengthMark.setColor(
        handleColor() == colorState.Default
          ? colorState.Vertical
          : handleColor(),
      );
      let length = endPoint.distanceTo(point1);
      length = MathTool.fixNumber(length, 0);
      lengthLabel && lengthLabel.update(length, findMid(point1, endPoint));
    }
    //构建边延长辅助线，用于显示垂线交点
    if (!inLine(linePoint1, linePoint2, nearPoint)) {
      const attrs = {
        vertexs: [
          getClosestPoint(linePoint1, linePoint2, nearPoint),
          nearPoint,
        ],
      };
      lineObj = new CSLine(attrs);
      const distance = attrs.vertexs[0].distanceTo(nearPoint);
      lineObj.setDashSize((distance / 10) * 0.7);
      lineObj.setGapSize((distance / 10) * 0.3);
      lineObj.setDashed(true);
      lineObj.setLineWidth(1);
      lineObj.setColor(colorState.Vertical);
      lineObj.setDashed(true);
      lineObj.addTo(measureGroup);
    }
    //初始化数据
    VerticalPoint = null;
    lengthMark = null;
    point1 = null;
    point2 = null;
    Snaper.clear();
    hoverEdge?.withdraw?.();
    hoverEdge = null;
    MState = '';
    ctx2.viewer.requestRender();
  } else if (step == 1 && hoverEdge?.length > 2) {
    step = 0;
    const center = geomInfo
      ? new Vector3().fromArray(geomInfo[0]?.axis[0])
      : null;
    // if (center.distanceTo(point1) - geomInfo[0].radius < 1e-5) {
    if (!center) {
      return;
    }
    if (lengthMark) {
      lengthMark.setVertexs([point1, center]);
      lengthMark.setColor(colorState.Default);
      let length = center.distanceTo(point1);
      length = MathTool.fixNumber(length, 0);
      lengthLabel && lengthLabel.update(length, findMid(point1, center));
    }
    // 新建一个圆点，绘制在圆心上
    const centerPoint = new CSPoint({ pointType: POINT_TYPE.CIRCLE_CENTER });
    centerPoint.setVertex(center);
    measureGroup.add(centerPoint);
    centerPoint.show();
    // } else {
    //   lengthMark.setVertexs([center, center])
    //   lengthLabel && lengthLabel.update('')
    // }
    radiusObjMove.destroy();
    radiusObjMove = null;
    //初始化数据
    VerticalPoint = null;
    lengthMark = null;
    point1 = null;
    point2 = null;
    Snaper.clear();
    hoverEdge?.withdraw?.();
    hoverEdge = null;
    MState = '';
    ctx2.viewer.requestRender();
  }
}

// 键盘事件
async function keyupEvent(e: EventsRes) {
  e.event.preventDefault();
  if (e.key == KEYBOARD_KEY.ESC) {
    if (step == 1) {
      hoverEdge?.withdraw?.();
      hoverEdge = null;
      if (lengthLabel || lengthMark) {
        measureGroup.remove(lengthMark);
        measureGroup.remove(lineObjmove);
        measureGroup.remove(lineObjmove1);
        measureGroup.remove(VerticalPoint);
        lengthLabel && measureGroup.remove(lengthLabel.labelObject);
      }
      resetVaria();
      ctx2.viewer.requestRender();
    } else if (step == 0) {
      if (measureGroup.children.length > 0) {
        SceneGraph.emptyGroup(measureGroup);
        ctx2.viewer.requestRender();
      } else {
        exit();
        close();
      }
    }
  }
  //方向键切换状态
  if (e.key == KEYBOARD_KEY.ARROWLEFT) {
    MState = measureState.Ylock;
  }
  if (e.key == KEYBOARD_KEY.ARROWRIGHT) {
    MState = measureState.Xlock;
  }
  if (e.key == KEYBOARD_KEY.ARROWUP) {
    MState = measureState.Zlock;
  }
  if (e.key == KEYBOARD_KEY.ARROWDOWN) {
    MState = measureState.Default;
  }
}

const exit = () => {
  MouseStyle.setName('');
  eventCenterManager.activeEventCenter
    .off(CENTEREVENTS.POINTERMOVE, onMouseMove)
    .off(CENTEREVENTS.POINTERUP, pointerUpEvent)
    .off(CENTEREVENTS.KEYUP, keyupEvent)
    .setDefault();

  Snaper.clear();
  measureGroup?.clear();
  toolsGroup?.remove(measureGroup);
  reset();
  ctx2.viewer.requestRender();
};

const initMeasure = (onClose: () => void) => {
  close = onClose;
  MouseStyle.setImg('measure', 0, 17);
  sceneSetup = ctx2.viewer.sceneSetup;
  toolsGroup = ctx2.cadScene.toolsGroup;
  measureGroup = new Object3D();
  toolsGroup.add(measureGroup);

  eventCenterManager.activeEventCenter
    .setState('measure')
    .on(CENTEREVENTS.POINTERMOVE, onMouseMove)
    .on(CENTEREVENTS.POINTERUP, pointerUpEvent)
    .on(CENTEREVENTS.KEYUP, keyupEvent)
    .addExit(close);
};

// 因生命周期需要增加的占位渲染
// sdk需要优化对纯函数命令的支持
const MeasureRender = ({ onClose }: { onClose: VoidFunction }) => {
  useEffect(() => {
    initMeasure(onClose);

    return () => {
      exit();
    };
  }, []);
  return <div />;
};

export const cmdMeasure: BaseCommand = {
  id: 'CmdMeasure',
  label: 'command.measure',
  icon: 'commands/feature/measure',
  create: (label: string, onClose: () => void) => (
    <MeasureRender onClose={onClose} />
  ),
};
